fix: prevent async generator cleanup errors in StreamableHTTP transport #1271
+2
−0
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Motivation and Context
Problem: The MCP SDK's
StreamableHTTPTransport
has a critical async resource cleanup bug in SSE handling that causes production failures in multi-task environments (using AnyIO like chainlit or langchain).Related Issues:
A similar one we're having in prod (we're not using Langchain though)
Root Cause: After investigating thoroughly, it turned out that in
_handle_sse_response()
and_handle_resumption_request()
, whenis_complete=True
, the loop breaks without properly closing the HTTP response connection. This leaves async generators not closed.Impact:
RuntimeError: async generator ignored GeneratorExit
Underlying Issue: The problem stems from httpx/httpcore async generator cleanup patterns. When SSE streams are terminated abruptly without proper cleanup, downstream async generators in the HTTP stack remain active, causing GeneratorExit exceptions.
How Has This Been Tested?
✅ Production Testing: Fix has been battle-tested in production FastMCP + Chainlit/langchain applications where the issue was consistently reproducible.
✅ Scenarios Tested:
✅ Results: Complete elimination of the error
RuntimeError: async generator ignored GeneratorExit
.Breaking Changes
None - This is a pure bug fix with no API changes. Existing code continues to work unchanged with improved reliability.
Types of changes
Checklist
Additional context
Technical Details: The fix ensures immediate HTTP response cleanup before generator exit, preventing downstream cleanup errors in httpx/httpcore. This aligns with best practices for async resource management in Python.
Alternative Approaches Considered:
Intuitively, trying to solve this tracking all called async generator down the road and make sure a proper closing is done (using aclosing from contextlib or adding finally like it was proposed here (Ensured explicit closing of async generators encode/httpx#3593) but it doesn't solve it. The only solution was by the proposed fix making sure to manually close the response resource (used for SSE stream).
Alternative Approaches Considered:
The only effective solution is explicit response resource cleanup at the SSE stream termination point, which this fix implements.
Production Impact: This 2-line fix resolves a blocking issue affecting multiple production applications using MCP in async frameworks. The workaround gist has proven the fix's effectiveness (waiting for an official fix).
Code Quality: Minimal. No performance impact.